package com.nio;

import org.junit.Test;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

public class DatagramDemo {
    @Test
    public void sendMessDemo() throws Exception {
        DatagramChannel server = DatagramChannel.open();
        InetSocketAddress address = new InetSocketAddress("127.0.0.1",10086);
        while (true){
            ByteBuffer byteBuffer = ByteBuffer.wrap("发送消息了".getBytes("UTF-8"));
            server.send(byteBuffer, address);
            System.out.println("已经发送完了");
            Thread.sleep(1000);
        }
    }

    @Test
    public void receiveMess() throws Exception {
        // 打开DatagramChannel
        DatagramChannel receiveChannel = DatagramChannel.open();
        InetSocketAddress address = new InetSocketAddress(10086);
        // 绑定
        receiveChannel.bind(address);
        // buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        while (true){
            byteBuffer.clear();
            SocketAddress receive = receiveChannel.receive(byteBuffer); // 接收
            byteBuffer.flip(); // 读写模式转换
            System.out.println(receive.toString());
            System.out.println(Charset.forName("UTF-8").decode(byteBuffer));
        }
    }

    @Test
    public void testConnect() throws IOException, InterruptedException {
        DatagramChannel server = DatagramChannel.open();
        InetSocketAddress address = new InetSocketAddress(10086);
        server.bind(address);
        server.connect(new InetSocketAddress("127.0.0.1",10086));

        server.write(ByteBuffer.wrap("发送消息了".getBytes("UTF-8")));
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        while (true){
            try {
                byteBuffer.clear();
                server.read(byteBuffer);
                byteBuffer.flip(); // 读写模式转换
                System.out.println(Charset.forName("UTF-8").decode(byteBuffer));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // Buffer
    @Test
    public void bufferTest() throws IOException {
        RandomAccessFile accessFile = new RandomAccessFile("F:\\test.txt", "rw");
        FileChannel inChannel = accessFile.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int read = inChannel.read(buffer);
        while (read != -1){
            buffer.flip(); // 读写模式转换
            while (buffer.hasRemaining()){
                System.out.println((char) buffer.get());
            }
            buffer.clear();
            read = inChannel.read(buffer);
        }
        accessFile.close();
    }

    @Test
    public void IntBufferTest() throws IOException {
        // 分配新的 int 缓冲区，参数为缓冲区容量
        // 新缓冲区的当前位置将为零，其界限(限制位置)将为其容量。
        // 它将具有一个底层实现数组，其数组偏移量将为零。
        IntBuffer intBuffer = IntBuffer.allocate(8);
        for (int i = 0; i < intBuffer.capacity(); i++) {
            int j=2*(i+1);
            // / 将给定整数写入此缓冲区的当前位置，当前位置递增
            intBuffer.put(j);
        }
        // 重设此缓冲区，将限制设置为当前位置，然后将当前位置设置为 0
        intBuffer.flip();
        // 查看在当前位置和限制位置之间是否有元素
        while (intBuffer.hasRemaining()){
            // 读取此缓冲区当前位置的整数，然后当前位置递增
            int i = intBuffer.get();
            System.out.println(i);
        }
    }

    @Test
    public void sliceBufferTest() throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        for (int i = 0; i < byteBuffer.capacity(); i++) {
            // / 将给定整数写入此缓冲区的当前位置，当前位置递增
            byteBuffer.put((byte)i);
        }
        // 重设此缓冲区，将限制设置为当前位置，然后将当前位置设置为 0
        byteBuffer.position(3);
        byteBuffer.limit(7);
        ByteBuffer slice = byteBuffer.slice();

        System.out.println("---slice->"+slice); // java.nio.HeapByteBuffer[pos=0 lim=4 cap=4]

        for (int i = 0; i < slice.capacity(); i++) {
            byte b = slice.get(i);
            b *=10;
            slice.put(i, b);
        }
        byteBuffer.position(0);
        byteBuffer.limit(byteBuffer.capacity());

        System.out.println("---->"+byteBuffer.capacity());
        while (byteBuffer.remaining()>0){
            System.out.println(byteBuffer.get());
        }
    }

    /**
     * 只读
     * @throws IOException
     */
    @Test
    public void onlyReadBufferTest() throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        for (int i = 0; i < byteBuffer.capacity(); i++) {
            // / 将给定整数写入此缓冲区的当前位置，当前位置递增
            byteBuffer.put((byte)i);
        }
        ByteBuffer byteBuffer_1 = byteBuffer.asReadOnlyBuffer(); // 创建只读缓冲区
        // 改变缓冲区内容
        for (int i = 0; i < byteBuffer.capacity(); i++) {
            byte b = byteBuffer.get(i);
            b *=10;
            byteBuffer.put(i, b);
        }
        byteBuffer_1.position(0);
        byteBuffer_1.limit(byteBuffer.capacity());

        while (byteBuffer_1.remaining()>0){
            System.out.println(byteBuffer_1.get());
        }
    }

    /**
     * 直接缓冲区
     * @throws IOException
     */
    @Test
    public void fileBufferTest() throws IOException {
        FileInputStream inputStream = new FileInputStream("F:\\1.txt");
        FileChannel inputChannel = inputStream.getChannel();

        FileOutputStream outputStream = new FileOutputStream("F:\\2.txt");
        FileChannel outputChannel = outputStream.getChannel();
        ByteBuffer allocate = ByteBuffer.allocate(1024); // 创建缓冲区大小
        while (true){
            allocate.clear();
            int read = inputChannel.read(allocate);
            if(read == -1){
                break;
            }
            allocate.flip(); // 切换读写模式
            outputChannel.write(allocate);
        }
    }

    static private final int srart = 0;
    static private final int size = 1024;
    // 内存映射文件io
    @Test
    public void mappendBuffer() throws IOException {
        RandomAccessFile rw = new RandomAccessFile("F:\\1.txt", "rw");
        FileChannel channel = rw.getChannel();
        MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, srart, size);
        mappedByteBuffer.put(0, (byte) 97);
        mappedByteBuffer.put(1023, (byte) 122);

        rw.close();
    }

    /**
     * Selector创建
     */
    @Test
    public void selector() throws IOException {
        Selector selector = Selector.open(); // 1,创建selector选择器
        //2,获取通道
        ServerSocketChannel socket = ServerSocketChannel.open();
        // 3,设置为非阻塞
        socket.configureBlocking(false);
        // 4,绑定连接
        socket.bind(new InetSocketAddress(9999));
        // 将通道注册到选择器上,并指定监听事件为: 接收事件
        socket.register(selector, SelectionKey.OP_ACCEPT);
        // 查询已经就绪的通道操作
        Set<SelectionKey> selectionKeys = selector.selectedKeys();
        // 遍历集合
        Iterator<SelectionKey> iterator = selectionKeys.iterator();
        while (iterator.hasNext()){
            SelectionKey key = iterator.next(); // 每个iterator的key
            // 判断key就绪状态操作
            if(key.isAcceptable()) {
                // a connection was accepted by a ServerSocketChannel.
            } else if (key.isConnectable()) {
                // a connection was established with a remote server.
            } else if (key.isReadable()) {
                // a channel is ready for reading
            } else if (key.isWritable()) {
                // a channel is ready for writing
            }
            iterator.remove();
        }
    }

    /**
     * 客户端
     * @throws IOException
     */
    @Test
    public void client() throws IOException {
        // 1,创建通道
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9999));
        // 2,切换非阻塞模式
        socketChannel.configureBlocking(false);
        //3,创建buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        // 4,写入buffer数据
        byteBuffer.put(new Date().toString().getBytes());
        // 5,模式切换
        byteBuffer.flip();
        // 6,写入通道
        socketChannel.write(byteBuffer);
        // 7,关闭
        byteBuffer.clear();
    }
    /**
     * 服务端
     */
    @Test
    public void serverDemo() throws IOException {
        // 1,获取服务端通道
        ServerSocketChannel ssc = ServerSocketChannel.open();
        // 2 切换读写模式
        ssc.configureBlocking(false);
        // 3,创建buffer
        ByteBuffer serverBuffer = ByteBuffer.allocate(1024);
        // 4,绑定端口号
        ssc.bind(new InetSocketAddress(9999));
        // 5,获取selector选择器
        Selector selector = Selector.open();
        // 6,通道注册到选择器,进行监听
        ssc.register(selector, SelectionKey.OP_ACCEPT);

        // 7,选择器进行轮询,进行后续操作
        while (selector.select()>0){
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                // 获取就需操作
                SelectionKey next = iterator.next();
                // 判断什么操作
                if(next.isAcceptable()){ // 接收就绪状态
                    // 获取连接
                    SocketChannel accept = ssc.accept();
                    // 切换非阻塞模式
                    accept.configureBlocking(false);
                    // 注册
                    accept.register(selector, SelectionKey.OP_READ);

                }else if(next.isReadable()){ //可读状态
                    SocketChannel channel = (SocketChannel) next.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    // 读取数据
                    int length = 0;
                    while ((length=channel.read(byteBuffer))>0){
                        byteBuffer.flip();
                        System.out.println(new String(byteBuffer.array(), 0, length));
                        byteBuffer.clear();
                    }
                }
            }
            iterator.remove();
        }
    }

}
